package model.constraints.inherited;

import java.util.ArrayList;
import java.util.Hashtable;

import automata.Fsa;
import automata.State;

import model.constraints.AbstractConstraint;
import model.constraints.synthesized.attributes.SyntAttributesAbstract;
import model.constraints.synthesized.attributes.SyntAttributesXDF;

public class ConfigurationXDF extends Configuration  {

	public ConfigurationXDF(State s, Fsa f, AbstractConstraint absConstraint) {
		super(s,f,absConstraint);
	}
	

	public SyntAttributesAbstract validateData(SyntAttributesAbstract syntAttAbs, String sb, String posAux, String nodeName,
			                           	Hashtable<String,ArrayList<Inters>> htIntersXfd)
	{
		SyntAttributesAbstract syntAttAux = new SyntAttributesXDF();
		SyntAttributesAbstract syntAtt = (SyntAttributesAbstract) syntAttAbs;		
		
		int dsj, npaths;
		
		if (isSourceEnd()) { //M =  T' ^ e = Ft' 
			//System.out.println("Fim do Source End");			
			syntAtt.setNodeName(nodeName);
			npaths = getConstraint().getNPaths();
			syntAtt.setDsSize(npaths);
			dsj = getPosition();
			String igualdade = constraint.getEquality(f, s);
						
			if(igualdade.equalsIgnoreCase("V"))
				syntAtt.setDs(sb,dsj);
			else
				syntAtt.setDs(posAux,dsj);
			
			for (int i=0;i<npaths;i++) {
				if ((i!=dsj) && syntAtt.getDs().get(i).equals(""))
				    syntAtt.setDs("#",i);
			}				
		} else {
			//System.out.println("nao eh fim do node");
			syntAtt.setNodeName(nodeName);
			npaths = getConstraint().getNPaths();
			syntAtt.setDsSize(npaths);
			
			for (int i=0;i<npaths;i++) {
				if (syntAtt.getDs().get(i).equals(""))
					syntAtt.setDs("#",i);					 
			}			
		}	   
		
		if (isTargetEnd()){ // M =  T" ^ e = Ft"
		   syntAtt.setNodeName(nodeName);
		   String igualdade = getEquality();
		   
		   if(igualdade.equalsIgnoreCase("V"))
			   syntAtt.setDc(sb);
		   else
			   syntAtt.setDc(posAux);		   	  
		} else {
			if (syntAtt.getDc().equals(""))
				syntAtt.setDc("#");
		} 
		
		Inters intersection1 = new Inters();
		intersection1.setDc(syntAtt.getDc());
	   	intersection1.setDs(syntAtt.getDs());
	    
	   	if (syntAtt.getInters().isEmpty())
	    	syntAtt.addInters(intersection1);
	    else {
	    	syntAttAux.addInters(intersection1);
	    	syntAtt.join(syntAttAux,htIntersXfd,posAux);
	    }    
	    
	   	return syntAtt;
	}
	
	public SyntAttributesAbstract validateInNode(SyntAttributesAbstract syntAtt, SyntAttributesAbstract syntAttAnt, 
     		String posAnt, String posAt, String nodeName, Hashtable<String, Hashtable<ArrayList<String>, String>> htContextXdf, 
     			Hashtable<String,ArrayList<Inters>> htIntersXfd, Hashtable<String, ArrayList<String>> hterror) {						

		Hashtable<ArrayList<String>, String> htXdf = new Hashtable<ArrayList<String>, String>();
		
		int role = roleType();
		int dsj;
		/*
		System.out.println("-- Role :"+role);
		System.out.println("-- Node Name :"+nodeName.toString());
		System.out.println("-- SyntAtt "+syntAtt.toString());
		System.out.println("-- SyntAttAnt "+syntAttAnt.toString());
		*/
		switch(role) {
			case 1: // Estado final para alguma dependencia, num no que nao eh folha, lado direito (eh isso?)
				syntAtt = validateData(syntAtt, syntAtt.getDc(), posAt, nodeName, htIntersXfd);
				syntAttAnt.join(syntAtt,htIntersXfd,posAnt);
				break;
			
			case 2: // in function validateData
				syntAtt.setNodeName(nodeName);
				dsj = getPosition();
				syntAtt = validateData(syntAtt,(String)syntAtt.getDs().get(dsj), posAt, nodeName, htIntersXfd);
				syntAttAnt.join(syntAtt,htIntersXfd,posAnt);
				break;
			
			case 3: // automata right side	
				if (!syntAtt.getDc().equals("") && !syntAtt.getDs().isEmpty()) { 
					syntAttAnt.join(syntAtt,htIntersXfd,posAnt);
					syntAtt.setDc("");
					syntAtt.setDs(new ArrayList<String>());
				} else 
					syntAttAnt.join(syntAtt,htIntersXfd,posAnt); 
				
				break;
			
			case 4: // automata left side		
				if (!syntAtt.getDc().equals("") && !syntAtt.getDs().isEmpty()) { 			   
					syntAttAnt.join(syntAtt,htIntersXfd,posAnt);
					syntAtt.setDc("");
					syntAtt.setDs(new ArrayList<String>());
				} else
					syntAttAnt.join(syntAtt,htIntersXfd,posAnt); 			     		
				
				break;
			
			case 5: // Context Automaton - Final State
				Boolean erro = false;
				
				
				for(Inters elInters: syntAtt.getInters()) {
				
					if (!htXdf.containsKey(elInters.getDs()))
						htXdf.put(elInters.getDs(), elInters.getDc());
					else {
						String s = (String) htXdf.get(elInters.getDs());
					
						if (!s.equals(elInters.getDc())) {
							erro = true;		
							//insert error in hash
							ArrayList<String> array = hterror.get(constraint.getNameConstraint());
							String dc = htXdf.get(elInters.getDs());
							array.add(elInters.getDs().toString() + " : " + elInters.getDc().toString() + " HAS KEY " + elInters.getDs().toString() + " : " + dc );					 			
							hterror.put(constraint.getNameConstraint(), array);					 	
						}    
					}	    
				}
				
				if (erro == false) 
					syntAttAnt.addC(true);
				else
					syntAttAnt.addC(false);
				
					htContextXdf.put(posAt, htXdf);				
					break;
			
            case 6:
                Boolean ver=true;
                
                ArrayList<Boolean> al2 = (ArrayList<Boolean>) syntAttAnt.getC();
                if (!al2.isEmpty()) {
                        for(Boolean element: al2) {
                        	ver = element && ver;
                        }
                } else 
                        ver = true;                             
                
                ArrayList<Boolean> al1 = (ArrayList<Boolean>) syntAtt.getC();
                for(Boolean element: al1) {
                	ver = element && ver;
                }
                
                ArrayList<Boolean> al3 = new ArrayList<Boolean>();
                al3.add(ver);
                syntAttAnt.setC(al3);                                   
                break;
                
            default:
                //working...
                break;			
		}
		
		return syntAttAnt;
	}	
	
	public String toString() {
		String str="";
		int fsaType;
		fsaType = ((AbstractConstraint) getConstraint()).getFsaPosition(getFsa());
		
		switch(fsaType){
			case 1: str += "M.";
					break;
			case 2: str += "T'.";
					break;
			case 3: str += "T\".";
					break;
		}
		
		str += "e"+(getState().elt);
		
		return str;
	}	
}
